package com.linln.admin.app.service.task;

import com.linln.admin.app.constants.AppConstants;
import com.linln.admin.app.constants.TaskTypeEnum;
import com.linln.admin.app.domain.AppInfo;
import com.linln.admin.app.domain.AppVersion;
import com.linln.admin.app.domain.RepoAccount;
import com.linln.admin.app.domain.VersionApp;
import com.linln.admin.app.service.branch.BranchHelper;
import com.linln.admin.system.domain.TaskQueue;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.NameFileFilter;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;

/**
 * 检查指定项目的一些规范是否正确：比如：release分支中是否有snapshot引用等。
 */
@Service
@Slf4j
public class CheckPmdTask extends AbstractTaskExecutor {
    /**
     * 是否可以处理这个任务
     *
     * @param t
     * @return
     */
    @Override
    public boolean support(TaskQueue t) {
        return t != null && TaskTypeEnum.CHECK_PMD.getType().equals(t.getType());
    }

    /**
     * 处理任务，并返回处理结果
     *
     * @param t
     * @return true-成功; 其它-false
     */
    @Override
    public boolean exec(TaskQueue t) {
        Long versionId = t.getRelate_id();
        Optional<AppVersion> ver = versionRepository.findById(versionId);
        if (!ver.isPresent()) {
            throw new IllegalArgumentException("对应的版本信息不存在！");
        }
        AppVersion version = ver.get();

        if (AppConstants.NO.equals(version.getCo_release_branch()) && AppConstants.NO.equals(version.getHotfix_flag())) {
            return true;//如果还没有切出release分支，则不需要检查
        }
        List<VersionApp> vas = versionAppRepository.findByVersionId(versionId);
        if (vas == null || vas.isEmpty()) {
            return true;
        }

        String baseVer = version.getVersion().trim().replace(" ", "");
        if (baseVer.startsWith(AppConstants.BRANCH_DEV_PREFIX)) {
            baseVer = baseVer.substring(4);
        }
        String release = AppConstants.BRANCH_RELEASE_PREFIX + baseVer;
        if (AppConstants.YES.equals(version.getHotfix_flag())) {
            release = AppConstants.BRANCH_HOTFIX_PREFIX + baseVer;
        }

        StringBuilder checkResult = new StringBuilder();
        for (VersionApp va : vas) {
            if (va == null || va.getApp_id() == null) {
                continue;
            }
            if (AppConstants.NO.equals(va.getHas_release()) && AppConstants.NO.equals(version.getHotfix_flag())) {
                continue;//如果没有release分支，则不处理
            }
            Optional<AppInfo> app = infoRepository.findById(va.getApp_id());
            if (!app.isPresent()) {
                versionAppRepository.delete(va);
                continue;
            }

            File dir = null;
            try {//将release代码切出来
                RepoAccount account = getRepoAccount(app.get().getRepo_account_id());
                dir = BranchHelper.findHandler(app.get().getRepo_type()).checkoutBranch(baseVer, app.get().getRepo_url(), account.getAccount(), account.getPass(), release);
                //开始检查里面的规范执行情况
                doCheckSnapshot(dir, checkResult);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                checkResult.append(app.get().getDisplay_name() + "发生错误！");
            } finally {
                try {
                    FileUtils.deleteDirectory(dir);
                } catch (Exception e) {
                    log.warn(e.getMessage(), e);
                }
            }
        }
        versionRepository.save(version);
        if (checkResult.length() > 0) {
            t.setMsg(checkResult.toString());
        }
        return true;
    }

    /**
     * 校验是否有snapshot引用
     *
     * @param dir         项目所在仓库目录
     * @param checkResult 检查结果，如果有内容，则表示有snapshot引用
     */
    public static void doCheckSnapshot(File dir, StringBuilder checkResult) {
        Iterator<File> poms = FileUtils.iterateFiles(dir, new NameFileFilter("pom.xml"), DirectoryFileFilter.DIRECTORY);
        String projectName = dir.getName();
        StringBuilder all = new StringBuilder();
        while (poms.hasNext()) {
            File pom = poms.next();
            SAXReader saxReader = new SAXReader();
            Document document = null;
            String pomFileName = FilenameUtils.getName(pom.getParent());
            try {
                document = saxReader.read(pom);
                Element element = document.getRootElement();
                //获取properties中定义的版本
                StringBuilder props = new StringBuilder();
                List<Element> eles = element.elements("properties");
                for (Element property : eles) {
                    for (Element ele : property.elements()) {
                        if (ele.getText().toLowerCase().endsWith("-snapshot")) {
                            props.append("\n      ");
                            props.append(ele.getName() + "=" + ele.getText());
                        }
                    }
                }

                //获取dependencies中定义的版本
                StringBuilder dependencies = new StringBuilder();
                eles = element.elements("dependencies");
                for (Element property : eles) {
                    for (Element depend : property.elements("dependency")) {
                        Element version = depend.element("version");
                        if (version == null) {
                            continue;
                        }
                        if (version.getText().toLowerCase().endsWith("-snapshot")) {
                            dependencies.append("\n      ");
                            dependencies.append(depend.element("artifactId").getText() + "=" + version.getText());
                        }
                    }
                }

                if (props.length() > 0 || dependencies.length() > 0) {
                    if(all.length()>0){
                        all.append("\n  ");
                    }
                    all.append(pomFileName + "\n    ");
                    if (props.length() > 0) {
                        all.append("properties" + props);
                    }
                    if (dependencies.length() > 0) {
                        all.append("dependencies" + dependencies);
                    }
                }
            } catch (Exception e) {
                throw new IllegalArgumentException("parse xml file failth : " + e);
            }
        }
        if (all.length() > 0) {
            if (checkResult.length() > 0) {
                checkResult.append("\n");
            }
            checkResult.append(projectName + "\n  " + all);
        }
    }
}
